package com.cheer.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.URLUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cheer.common.Page;
import com.cheer.common.ResultEnum;
import com.cheer.dao.*;
import com.cheer.dto.MallOrderAddDTO;
import com.cheer.dto.MallOrderDeliverDTO;
import com.cheer.dto.MallOrderQueryDTO;
import com.cheer.dto.MallOrderRefundApplyDTO;
import com.cheer.entity.*;
import com.cheer.enums.*;
import com.cheer.exception.ServiceException;
import com.cheer.service.*;
import com.cheer.utils.ExcelsUtil;
import com.cheer.utils.QRCodeUtil;
import com.cheer.utils.RandomUtil;
import com.cheer.vo.*;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service("mallOrderService")
public class MallOrderServiceImpl extends ServiceImpl<MallOrderDao, MallOrderEntity> implements MallOrderService {

    @Value("${shop.url}")
    private String shopUrl;

    @Value("${image.url}")
    private String imageUrl;

    @Value("${image.dir}")
    private String imageDir;

    @Autowired
    private MallOrderDao mallOrderDao;

    @Autowired
    private OaUserService oaUserService;

    @Autowired
    private MallCreditRecordService mallCreditRecordService;

    @Autowired
    private MallSalesroomService mallSalesroomService;

    @Autowired
    private MallProductService mallProductService;

    @Autowired
    private MallProductAttrService mallProductAttrService;

    @Autowired
    private MallAddressService mallAddressService;

    @Autowired
    private MallProductImageService mallProductImageService;

    @Autowired
    private MallOrderFinishService mallOrderFinishService;

    @Autowired
    private WxPayService wxPayService;

    private Snowflake snowflake = new Snowflake(1L, 1L);

    @Override
    public Page<MallOrderListVO> listByQueryCondition(MallOrderQueryDTO orderQueryDTO) {
        IPage<MallOrderEntity> page = mallOrderDao.selectPageByQueryCondition(orderQueryDTO);

        List<Long> salesroomIdList = page.getRecords().stream()
                .filter(orderEntity -> orderEntity.getSalesroomId() != null)
                .map(MallOrderEntity::getSalesroomId)
                .collect(Collectors.toList());
        Map<Long, MallSalesroomEntity> salesroomMap = CollectionUtils.isEmpty(salesroomIdList) ? new HashMap<>() :
                mallSalesroomService.listByIds(salesroomIdList).stream()
                        .collect(Collectors.toMap(MallSalesroomEntity::getId, Function.identity()));

        List<MallOrderListVO> orderList = page.getRecords().stream()
                .map(orderEntity -> {

                    // 基本信息
                    MallOrderListVO orderListVO = new MallOrderListVO()
                            .setId(orderEntity.getId())
                            .setNumber(orderEntity.getNumber())
                            .setType(orderEntity.getType())
                            .setPhone(orderEntity.getPhone())
                            .setAddress(orderEntity.getAddress())
                            .setRemark(orderEntity.getRemark())
                            .setCreateTime(DateUtil.formatDateTime(orderEntity.getCreateTime()))
                            .setQuantity(orderEntity.getQuantity())
                            .setStatus(orderEntity.getStatus())
                            .setRefundStatus(orderEntity.getRefundStatus())
                            .setIsSettle(orderEntity.getIsSettle());

                    OaUserEntity user = oaUserService.getById(orderEntity.getUserId());
                    if (user != null) {
                        orderListVO.setMemberName(user.getName())
                                .setNickname(user.getNickname())
                                .setHeadImg(user.getHeadimgurl());
                    }

                    OaCertVO cert = oaUserService.cert(orderEntity.getUserId());
                    if (cert.getIsCert()) {
                        orderListVO.setCertNumber(cert.getCertNumber());
                        orderListVO.setRealName(cert.getRealName());
                    }

                    if (StringUtils.isNotBlank(orderEntity.getAttrValue())) {
                        orderListVO.setProductName(orderEntity.getProductName() + "（" + orderEntity.getAttrValue() + "）");
                    } else {
                        orderListVO.setProductName(orderEntity.getProductName());
                    }

                    // 价格
                    BigDecimal productFee = new BigDecimal(0);
                    if (orderEntity.getPrice() != null) {
                        orderListVO.setPrice(orderEntity.getPrice().stripTrailingZeros().toPlainString() + "元");
                        productFee = orderEntity.getPrice().multiply(new BigDecimal(orderEntity.getQuantity()));
                    }
                    if (!orderEntity.getPostage() && orderEntity.getPostagePrice() != null) {
                        productFee = productFee.add(orderEntity.getPostagePrice());
                    }
                    orderListVO.setPrice(productFee.stripTrailingZeros().toPlainString() + "元");

                    // 物流或电子券码信息
                    if (Objects.equals(MallProductTypeEnum.OBJECT.getCode(), orderEntity.getType())) {
                        orderListVO.setExpressInfo(orderEntity.getExpressInfo());
                    } else if (Objects.equals(MallProductTypeEnum.VIR_OBJECT.getCode(), orderEntity.getType())) {
                        if (Objects.equals(MallProductVirTypeEnum.ELE_OBJECT.getCode(), orderEntity.getVirType())) {
                            String ticketInfo = "券码编号：" + orderEntity.getVirNumber();
                            if (orderEntity.getSalesroomId() != null) {
                                MallSalesroomEntity salesroom = salesroomMap.get(orderEntity.getSalesroomId());
                                if (salesroom != null) {
                                    ticketInfo += " 门店名称：" + salesroom.getName();
                                }
                            }
                            if (orderEntity.getHexiaoNumber() != null) {
                                ticketInfo += " 凭证编号：" + orderEntity.getHexiaoNumber();
                            }
                            orderListVO.setExpressInfo(ticketInfo);
                        }
                    }

                    if (Objects.equals(MallRefundStatusEnum.TO_REFUND.getCode(), orderEntity.getRefundStatus()) &&
                            orderEntity.getRefundCount() > 1) {
                        orderListVO.setRefundNotice(true);
                    }

                    return orderListVO;

                })
                .collect(Collectors.toList());

        return new Page<>(page, orderList);
    }

    @Override
    public void download(MallOrderQueryDTO orderQueryDTO, HttpServletResponse response) {
        List<MallOrderEntity> list = mallOrderDao.selectListByQueryCondition(orderQueryDTO);

        List<Long> salesroomIdList = list.stream()
                .filter(orderEntity -> orderEntity.getSalesroomId() != null)
                .map(MallOrderEntity::getSalesroomId)
                .collect(Collectors.toList());
        Map<Long, MallSalesroomEntity> salesroomMap = CollectionUtils.isEmpty(salesroomIdList) ? new HashMap<>() :
                mallSalesroomService.listByIds(salesroomIdList).stream()
                        .collect(Collectors.toMap(MallSalesroomEntity::getId, Function.identity()));

        List<MallOrderListVO> orderList = list.stream()
                .map(orderEntity -> {

                    // 基本信息
                    MallOrderListVO orderListVO = new MallOrderListVO()
                            .setId(orderEntity.getId())
                            .setNumber(orderEntity.getNumber())
                            .setType(orderEntity.getType())
                            .setPhone(orderEntity.getPhone())
                            .setAddress(orderEntity.getAddress())
                            .setRemark(orderEntity.getRemark())
                            .setCreateTime(DateUtil.formatDateTime(orderEntity.getCreateTime()))
                            .setQuantity(orderEntity.getQuantity())
                            .setStatus(orderEntity.getStatus())
                            .setRefundStatus(orderEntity.getRefundStatus())
                            .setIsSettle(orderEntity.getIsSettle());

                    try {
                        OaUserInfoVO userInfoVO = oaUserService.info(orderEntity.getUserId());
                        if (userInfoVO != null) {
                            orderListVO.setMemberName(userInfoVO.getName())
                                    .setLearnClass(userInfoVO.getLearnClass());
                        }
                    } catch (Exception ignore) {
                    }

                    if (StringUtils.isNotBlank(orderEntity.getAttrValue())) {
                        orderListVO.setProductName(orderEntity.getProductName() + "（" + orderEntity.getAttrValue() + "）");
                    } else {
                        orderListVO.setProductName(orderEntity.getProductName());
                    }

                    // 价格
                    BigDecimal productFee = new BigDecimal(0);
                    if (orderEntity.getPrice() != null) {
                        orderListVO.setPrice(orderEntity.getPrice().stripTrailingZeros().toPlainString() + "元");
                        productFee = orderEntity.getPrice().multiply(new BigDecimal(orderEntity.getQuantity()));
                    }
                    if (!orderEntity.getPostage() && orderEntity.getPostagePrice() != null) {
                        productFee = productFee.add(orderEntity.getPostagePrice());
                    }
                    orderListVO.setPrice(productFee.stripTrailingZeros().toPlainString() + "元");

                    // 物流或电子券码信息
                    if (Objects.equals(MallProductTypeEnum.OBJECT.getCode(), orderEntity.getType())) {
                        orderListVO.setExpressInfo(orderEntity.getExpressInfo());
                    } else if (Objects.equals(MallProductTypeEnum.VIR_OBJECT.getCode(), orderEntity.getType())) {
                        if (Objects.equals(MallProductVirTypeEnum.ELE_OBJECT.getCode(), orderEntity.getVirType())) {
                            String ticketInfo = "券码编号：" + orderEntity.getVirNumber();
                            if (orderEntity.getSalesroomId() != null) {
                                MallSalesroomEntity salesroom = salesroomMap.get(orderEntity.getSalesroomId());
                                if (salesroom != null) {
                                    ticketInfo += " 门店名称：" + salesroom.getName();
                                }
                            }
                            if (orderEntity.getHexiaoNumber() != null) {
                                ticketInfo += " 凭证编号：" + orderEntity.getHexiaoNumber();
                            }
                            orderListVO.setExpressInfo(ticketInfo);
                        }
                    }

                    if (Objects.equals(MallRefundStatusEnum.TO_REFUND.getCode(), orderEntity.getRefundStatus()) &&
                            orderEntity.getRefundCount() > 1) {
                        orderListVO.setRefundNotice(true);
                    }

                    return orderListVO;

                })
                .collect(Collectors.toList());

        List<Map<String, Object>> excelList = new ArrayList<>();
        Map<String, Object> header = new HashMap<>();
        header.put("sheetName", "订单表");
        excelList.add(header);

        for (MallOrderListVO orderListVO : orderList) {
            Map<String, Object> line = new HashMap<>();
            line.put("number", orderListVO.getNumber());
            line.put("productName", orderListVO.getProductName());
            line.put("memberName", orderListVO.getMemberName());
            line.put("learnClass", orderListVO.getLearnClass());
            line.put("phone", orderListVO.getPhone());
            line.put("address", orderListVO.getAddress());
            line.put("price", orderListVO.getPrice());
            line.put("remark", orderListVO.getRemark());
            line.put("createTime", orderListVO.getCreateTime());
            line.put("quantity", orderListVO.getQuantity());
            line.put("expressInfo", orderListVO.getExpressInfo());
            line.put("status", MallOrderStatusEnum.forCode(orderListVO.getStatus()));
            line.put("refundStatus", MallRefundStatusEnum.forCode(orderListVO.getRefundStatus()));
            line.put("isSettle", orderListVO.getIsSettle() ? "已结算" : "未结算");
            excelList.add(line);
        }

        String[] columnNames = {"订单编号", "产品名称", "购物人", "单位", "手机", "收货地址", "价格", "备注", "订单时间",
                "数量", "快递信息", "状态", "退款状态", "与商家结算状态"};
        String[] keys = {"number", "productName", "memberName", "learnClass", "phone", "address", "price", "remark",
                "createTime", "quantity", "expressInfo", "status", "refundStatus", "isSettle"};

        response.setContentType("application/x-download");
        response.addHeader("Content-Disposition", "attachment;filename=订单表.xlsx;filename*=UTF-8''"
                + URLUtil.encode("订单表.xlsx"));
        try (SXSSFWorkbook xssfWorkbook = ExcelsUtil.ExcelSingleOutputStream(excelList, keys, columnNames)) {
            xssfWorkbook.write(response.getOutputStream());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ServiceException("下载异常");
        }
    }

    @Override
    public void importOrder(MultipartFile file) {
        XSSFWorkbook workBook;
        try {
            workBook = new XSSFWorkbook(file.getInputStream());
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new ServiceException("导入异常");
        }

        XSSFSheet sheet = workBook.getSheetAt(0);

        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            if (row != null) {

                String orderNumber;
                String settle = null;

                Cell cell = row.getCell(0);
                if (cell == null) {
                    continue;
                }

                if (cell.getCellTypeEnum() == CellType.NUMERIC) {
                    orderNumber = String.valueOf(cell.getNumericCellValue());
                } else {
                    orderNumber = cell.getStringCellValue();
                }

                cell = row.getCell(13);
                if (cell != null) {
                    settle = cell.getStringCellValue();
                }

                boolean isSettle = "已结算".equals(settle);

                MallOrderEntity mallOrderEntity = new MallOrderEntity()
                        .setIsSettle(isSettle);
                mallOrderDao.update(mallOrderEntity, new QueryWrapper<MallOrderEntity>()
                        .eq("number", orderNumber));
            }
        }
    }

    @Override
    public void importOrderExpress(MultipartFile file) {
        XSSFWorkbook workBook;
        try {
            workBook = new XSSFWorkbook(file.getInputStream());
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            throw new ServiceException("导入异常");
        }

        XSSFSheet sheet = workBook.getSheetAt(0);

        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            if (row != null) {

                String orderNumber;
                String expressInfo = null;

                Cell cell = row.getCell(0);
                if (cell == null) {
                    continue;
                }

                if (cell.getCellTypeEnum() == CellType.NUMERIC) {
                    orderNumber = String.valueOf(cell.getNumericCellValue());
                } else {
                    orderNumber = cell.getStringCellValue();
                }

                if (StringUtils.isBlank(orderNumber)) {
                    continue;
                }

                MallOrderEntity order = mallOrderDao.selectByOrderNumber(orderNumber);
                if (!Objects.equals(order.getType(), MallProductTypeEnum.OBJECT.getCode())) {
                    continue;
                }

                cell = row.getCell(10);
                if (cell != null) {
                    cell.setCellType(CellType.STRING);
                    expressInfo = cell.getStringCellValue();
                }

                boolean isExpressed = StringUtils.isNotBlank(expressInfo);
                if (!isExpressed) {
                    continue;
                }

                MallOrderEntity mallOrderEntity = new MallOrderEntity()
                        .setExpressInfo(expressInfo);
                if (Objects.equals(order.getStatus(), MallOrderStatusEnum.TO_DELIVER.getCode())) {
                    mallOrderEntity.setStatus(MallOrderStatusEnum.DELIVERED.getCode());
                }

                mallOrderDao.update(mallOrderEntity, new QueryWrapper<MallOrderEntity>()
                        .eq("number", orderNumber));
            }
        }
    }

    @Override
    @Transactional
    public LotteryVO startLottery(Integer userId) {
        Integer credit = oaUserService.getShoppingCredit(userId);
        if (credit == null) {
            throw new ServiceException("用户不存在");
        }
        int consumeCredit = 50;
        if (credit < consumeCredit) {
            throw new ServiceException("积分不足");
        }
        // 扣除积分
        oaUserService.consumeCredit(userId, consumeCredit);

        // 抽奖
        Long awardId = lotteryAlgorithm(userId);
        if (awardId == 0) {
            return new LotteryVO().setLucky(awardId);
        }

        // 插入中奖记录
        MallAwardRecordEntity awardRecord = new MallAwardRecordEntity();
        awardRecord.setUserId(userId);
        awardRecord.setAwardId(awardId);
        awardRecord.setSubmitted(false);
        mallAwardRecordDao.insert(awardRecord);

        MallAwardEntity awardEntity = mallAwardDao.selectById(awardRecord.getAwardId());
        MallProductFrontInfoVO product = mallProductService.frontInfo(awardEntity.getProductId());
        lotteryCacheDao.addAnnouncement(String.format(ANNOUNCEMENT_PATTERN,
                oaUserService.getById(userId).getName(), product.getName()));

        return new LotteryVO().setLucky(awardId).setProduct(product);
    }

    @Autowired
    private MallAwardDao mallAwardDao;

    @Override
    public LotteryVO award(Integer userId) {
        MallAwardRecordEntity awardRecord = mallAwardRecordDao.selectOne(new QueryWrapper<MallAwardRecordEntity>()
                .eq("user_id", userId).eq("submitted", false).last("limit 1"));
        if (awardRecord == null) {
            return new LotteryVO().setLucky(0L);
        }
        MallAwardEntity awardEntity = mallAwardDao.selectById(awardRecord.getId());
        MallProductFrontInfoVO product = mallProductService.frontInfo(awardEntity.getProductId());
        return new LotteryVO().setLucky(awardRecord.getId()).setProduct(product);
    }

    @Override
    public List<String> getLotteryAnnouncement() {
        return lotteryCacheDao.getAnnouncement();
    }

    static final String ANNOUNCEMENT_PATTERN = "恭喜 %s 获得 %s";

    @Autowired
    private MallAwardRecordDao mallAwardRecordDao;

    @Autowired
    private PrizeCacheDao prizeCacheDao;

    @Autowired
    private LotteryCacheDao lotteryCacheDao;

    private Long lotteryAlgorithm(Integer userId) {
        MallAwardRecordEntity awardRecord = mallAwardRecordDao.selectOne(new QueryWrapper<MallAwardRecordEntity>()
                .eq("user_id", userId).last("limit 1"));
        if (awardRecord != null) {
            return 0L;
        }

        String awardId = prizeCacheDao.getPrize();
        if (awardId == null) {
            return 0L;
        }
        return Long.valueOf(awardId);
    }

    @Override
    public MallOrderInfoVO info(Long id) {
        MallOrderEntity orderEntity = mallOrderDao.selectById(id);
        if (orderEntity == null) {
            throw new ServiceException("订单不存在");
        }

        MallOrderInfoVO orderInfoVO = new MallOrderInfoVO()
                .setId(orderEntity.getId())
                .setNumber(orderEntity.getNumber())
                .setMemberName(oaUserService.getUsernameById(orderEntity.getUserId()))
                .setRemark(orderEntity.getRemark())
                .setQuantity(orderEntity.getQuantity())
                .setReceiver(orderEntity.getReceiver())
                .setPhone(orderEntity.getPhone())
                .setAddress(orderEntity.getAddress());

        if (StringUtils.isNotBlank(orderEntity.getAttrValue())) {
            orderInfoVO.setProductName(orderEntity.getProductName() + "(" + orderEntity.getAttrValue() + ")");
        } else {
            orderInfoVO.setProductName(orderEntity.getProductName());
        }

        if (orderEntity.getPrice() != null) {
            orderInfoVO.setPrice(orderEntity.getPrice().stripTrailingZeros().toPlainString() + "元");
        }

        return orderInfoVO;
    }

    @Override
    @Transactional
    public void deliver(MallOrderDeliverDTO orderDeliverDTO, MallOrderEntity orderEntity) {
        if (!(Objects.equals(orderEntity.getType(), MallProductTypeEnum.OBJECT.getCode()) &&
                Objects.equals(orderEntity.getStatus(), MallOrderStatusEnum.TO_DELIVER.getCode()))) {
            throw new ServiceException("只有待发货状态的实体商品订单可以进行发货操作");
        }

        MallOrderEntity updateOrder = new MallOrderEntity()
                .setId(orderDeliverDTO.getId())
                .setExpressInfo(orderDeliverDTO.getExpressInfo())
                .setStatus(MallOrderStatusEnum.DELIVERED.getCode())
                .setDeliverTime(new Date());

        mallOrderDao.updateById(updateOrder);

        MallOrderFinishEntity orderFinish = new MallOrderFinishEntity()
                .setOrderId(orderDeliverDTO.getId())
                .setFinishTime(DateUtil.offsetDay(updateOrder.getDeliverTime(), 8));

        mallOrderFinishService.save(orderFinish);
    }

    @Override
    public MallRefundInfoVO getRefundInfo(Long id) {
        MallOrderEntity orderEntity = mallOrderDao.selectById(id);
        if (orderEntity == null) {
            throw new ServiceException("订单不存在");
        }

        return new MallRefundInfoVO()
                .setId(orderEntity.getId())
                .setPhone(orderEntity.getRefundPhone())
                .setExplain(orderEntity.getExplain());
    }

    @Override
    @Transactional
    public void agreeRefund(MallOrderEntity order) {
        if (order.getIsSettle()) {
            throw new ServiceException("已核算的订单不可以进行退款操作");
        }

        if (!Objects.equals(order.getRefundStatus(), MallRefundStatusEnum.TO_REFUND.getCode())) {
            throw new ServiceException("只有待退款的订单可以进行退款操作");
        }

        if (order.getPrice() != null && order.getPrice().compareTo(new BigDecimal("0")) > 0) {
            WxPayRefundRequest refundRequest = new WxPayRefundRequest();
            refundRequest.setOutTradeNo(order.getNumber());
            refundRequest.setOutRefundNo(String.valueOf(snowflake.nextId()));

            BigDecimal productFee = order.getPrice().multiply(new BigDecimal(order.getQuantity()));
            if (!order.getPostage() && order.getPostagePrice() != null) {
                productFee = productFee.add(order.getPostagePrice());
            }
            refundRequest.setTotalFee(BaseWxPayRequest.yuanToFen(productFee.stripTrailingZeros().toPlainString()));//元转成分

            if (!order.getPostage() && order.getPostagePrice() != null &&
                    Objects.equals(order.getStatus(), MallOrderStatusEnum.DELIVERED.getCode())) {
                productFee = productFee.subtract(order.getPostagePrice());
            }
            refundRequest.setRefundFee(BaseWxPayRequest.yuanToFen(productFee.stripTrailingZeros().toPlainString()));//元转成分

            try {
                wxPayService.refund(refundRequest);
            } catch (WxPayException e) {
                log.error(e.getMessage(), e);
                throw new ServiceException("退款失败，请稍后重试！");
            }
        }

        if (order.getCredit() != null && order.getCredit() > 0) {

            int consumeCredit = order.getCredit() * order.getQuantity();
            if(order.getExchangeType() == null || ExchangeTypeEnum.INTEGRAL.getCode().equals(order.getExchangeType())){
                // 退还积分
                oaUserService.refundCredit(order.getUserId(), consumeCredit);
            }else{
                // 退还小红花
                oaUserService.refundFlower(order.getUserId(), consumeCredit);
            }
            // 增加积分记录
            MallCreditRecordEntity record = new MallCreditRecordEntity()
                    .setUserId(order.getUserId())
                    .setName("商品退款")
                    .setCredit(consumeCredit)
                    .setDate(DateUtil.format(new Date(), "yyyy-MM-dd"));
            mallCreditRecordService.save(record);
        }

        // 更改订单状态
        MallOrderEntity updateOrder = new MallOrderEntity()
                .setId(order.getId())
                .setStatus(MallOrderStatusEnum.CLOSED.getCode())
                .setRefundStatus(MallRefundStatusEnum.REFUNDED.getCode())
                .setProcessTime(new Date());
        mallOrderDao.updateById(updateOrder);

        // 增加库存
        mallProductService.addStock(order.getProductId(), order.getQuantity());
    }

    @Override
    @Transactional
    public void rejectRefund(MallOrderEntity orderEntity, String reply) {
        if (!Objects.equals(orderEntity.getRefundStatus(), MallRefundStatusEnum.TO_REFUND.getCode())) {
            throw new ServiceException("只有待退款的订单可以进行拒绝退款操作");
        }

        // 更改订单状态
        MallOrderEntity updateOrder = new MallOrderEntity()
                .setId(orderEntity.getId())
                .setRefundStatus(MallRefundStatusEnum.REJECTED.getCode())
                .setReply(reply)
                .setProcessTime(new Date());
        mallOrderDao.updateById(updateOrder);

        // 延长自动收货时间
        if (Objects.equals(MallProductTypeEnum.OBJECT.getCode(), orderEntity.getType()) && orderEntity.getDeliverTime() != null) {
            mallOrderFinishService.updateFinishTimeByOrderId(orderEntity.getId(),
                    DateUtil.offsetDay(orderEntity.getDeliverTime(), 15));
        }
    }

    @Override
    public List<MallOrderEntity> listFinishedSimplyByShopId(Long shopId) {
        return mallOrderDao.selectPriceAndQuantityByShopIdAndFinished(shopId);
    }

    @Override
    public List<MallOrderEntity> listByStatus(List<Integer> statusList) {
        if (CollectionUtils.isEmpty(statusList)) {
            return new ArrayList<>();
        }

        return mallOrderDao.selectListByStatus(statusList);
    }

    @Override
    public List<MallOrderEntity> listByShopIdAndStatus(Long shopId, List<Integer> statusList) {
        if (CollectionUtils.isEmpty(statusList)) {
            return new ArrayList<>();
        }

        return mallOrderDao.selectListByShopIdAndStatus(shopId, statusList);
    }

    @Override
    public Long getShopIdByVirNumber(String virNumber) {
        return mallOrderDao.selectShopIdByVirNumber(virNumber);
    }

    @Override
    public MallOrderEntity getByVirNumber(String virNumber) {
        return mallOrderDao.selectByVirNumber(virNumber);
    }

    @Override
    @Transactional
    public MallOrderCreateVO add(MallOrderAddDTO orderAddDTO, Integer userId, String openid, String ip) {
        MallProductEntity product = mallProductService.getById(orderAddDTO.getProductId());
        if (product == null) {
            throw new ServiceException("商品不存在");
        }
        if (!Objects.equals(product.getPublishStatus(), MallProductStatusEnum.PASSED.getCode())) {
            throw new ServiceException("商品没有上架");
        }
        // 小红花产品
        if(ExchangeTypeEnum.FLOWER.getCode().equals(product.getExchangeType())){

            // 每个账号每日只可兑换一个小红花的产品
            List<MallOrderEntity> toDayOrders = mallOrderDao.selectToDayOrderByExchType(product.getExchangeType(), userId);
            if(CollectionUtils.isNotEmpty(toDayOrders)){
                throw new ServiceException("每个账号每日只可兑换一个小红花的产品!");
            }
            // 每个产品，每周只允许一个账号兑换一次
            List<MallOrderEntity> weekOrders = mallOrderDao.selectThisWeekOrderByPid(product.getId(), userId);
            if(CollectionUtils.isNotEmpty(weekOrders)){
                throw new ServiceException("每个产品，每周只允许一个账号兑换一次!");
            }
        }
        // 积分产品
        else if (product.getLimited()) {
            if(mallOrderDao.selectOneByUserIdAndProductId(userId, product.getId()) != null){
                throw new ServiceException(ResultEnum.LIMITED);    
            }
            // 大学习单独查询
            Long dxxShopId = 21l;
            List<MallProductEntity> mallProductEntitys = mallProductService.listByShopId(dxxShopId);

            if(CollectionUtils.isNotEmpty(mallProductEntitys)){
                List<Long> dxxProductIds = mallProductEntitys.stream().map(MallProductEntity::getId).collect(Collectors.toList());
                // 查询当月是否购买过大学习产品
                if(dxxProductIds.contains(product.getId())){
                    List<MallOrderEntity> lists = mallOrderDao.selectListByUserIdAndProductIds(userId, Lists.newArrayList(dxxProductIds));
                    if(CollectionUtils.isNotEmpty(lists)){
                        throw new ServiceException("已抢光 请等待下次开启");
                    }
                }
            }

        }

        MallAddressListVO addressListVO = mallAddressService.listById(orderAddDTO.getAddressId());
        if (addressListVO == null) {
            throw new ServiceException("收货信息不存在");
        }

        MallProductAttrEntity productAttr = mallProductAttrService.getByProductIdAndValue(orderAddDTO.getProductId(),
                orderAddDTO.getAttrValue());
        if (productAttr == null) {
            throw new ServiceException("规格属性不存在");
        }

        // 消耗TOKEN
        if (product.getCredit() != null && product.getCredit() > 0) {
            int consumeCredit = product.getCredit() * orderAddDTO.getQuantity();
            oaUserService.consume(userId, consumeCredit, product.getExchangeType());
        }

        // 锁定库存
        if (!mallProductService.minusStock(orderAddDTO.getProductId(), orderAddDTO.getQuantity())) {
            throw new ServiceException("库存不足");
        }

        MallOrderEntity order = new MallOrderEntity()
                .setNumber(String.valueOf(snowflake.nextId()))
                .setProductId(product.getId())
                .setProductName(product.getMainTitle())
                .setType(product.getType())
                .setExchangeType(product.getExchangeType())
                .setAttrValue(orderAddDTO.getAttrValue())
                .setThumbnailUrl(mallProductImageService.getThumbnailByProductId(product.getId()))
                .setUserId(userId)
                .setShopId(product.getShopId())
                .setPrice(productAttr.getDisplayPrice())
                .setCredit(productAttr.getCredit())
                .setPostage(product.getPostage())
                .setPostagePrice(product.getPostagePrice())
                .setRemark(orderAddDTO.getRemark())
                .setQuantity(orderAddDTO.getQuantity())
                .setVirType(product.getVirType())
                .setAllowRefund(product.getAllowRefund());

        if (addressListVO != null) {
            order.setReceiver(addressListVO.getReceiver())
                    .setPhone(addressListVO.getPhone())
                    .setAddress(addressListVO.getAddress());
        }

        if (product.getLottery()) {
            MallAwardEntity awardEntity = mallAwardDao.selectOne(new QueryWrapper<MallAwardEntity>()
                    .eq("product_id", product.getId()).last("limit 1"));
            MallAwardRecordEntity awardRecord = mallAwardRecordDao.selectOne(new QueryWrapper<MallAwardRecordEntity>()
                    .eq("user_id", userId).eq("award_id", awardEntity.getId()).last("limit 1"));
            if (awardRecord.getSubmitted()) {
                throw new ServiceException("不允许重复提交订单");
            }
            awardRecord.setSubmitted(true);
            mallAwardRecordDao.updateById(awardRecord);
        }

        if ((productAttr.getDisplayPrice() != null && productAttr.getDisplayPrice().compareTo(new BigDecimal("0")) > 0)
                || (!product.getPostage() && product.getPostagePrice().compareTo(new BigDecimal("0")) > 0)) {
            // 需要付款
            order.setStatus(MallOrderStatusEnum.TO_PAY.getCode());

            mallOrderDao.insert(order);

            return createWxOrder(openid, ip, order);

        } else {
            // 不需要付款
            order.setStatus(MallOrderStatusEnum.TO_DELIVER.getCode());

            // 生成电子券码
            processVirObject(order);

            mallOrderDao.insert(order);

            int consumeCredit = order.getCredit() * order.getQuantity();
            MallCreditRecordEntity creditRecord = new MallCreditRecordEntity()
                    .setUserId(order.getUserId())
                    .setName("商品兑换")
                    .setCredit(consumeCredit * -1)
                    .setDate(DateUtil.format(new Date(), "yyyy-MM-dd"));
            mallCreditRecordService.save(creditRecord);

            return new MallOrderCreateVO()
                    .setId(order.getId())
                    .setPay(false);
        }
    }

    @Override
    public List<MallOrderFrontListVO> listByUserId(Integer userId, Integer status) {
        List<MallOrderEntity> orderList = mallOrderDao.selectListByUserIdAndStatus(userId, status);

        return convertList(orderList);
    }

    @Override
    public List<MallOrderFrontListVO> listRefundByUserId(Integer userId) {
        List<MallOrderEntity> orderList = mallOrderDao.selectRefundListByUserId(userId);

        return convertList(orderList);
    }

    @Override
    public MallExpressInfoVO getExpress(Long id) {
        MallOrderEntity orderEntity = mallOrderDao.selectById(id);
        if (orderEntity == null) {
            throw new ServiceException("订单不存在");
        }

        return new MallExpressInfoVO()
                .setOrderNumber(orderEntity.getNumber())
                .setExpressInfo(orderEntity.getExpressInfo())
                .setAddress(orderEntity.getAddress());
    }

    @Override
    public MallOrderFrontInfoVO frontInfo(Long id) {
        MallOrderEntity orderEntity = mallOrderDao.selectById(id);
        if (orderEntity == null) {
            throw new ServiceException("订单不存在");
        }

        MallOrderFrontInfoVO mallOrderFrontInfoVO = new MallOrderFrontInfoVO();
        BeanUtil.copyProperties(orderEntity, mallOrderFrontInfoVO);

        mallOrderFrontInfoVO.setCreateDate(orderEntity.getCreateTime());
        mallOrderFrontInfoVO.setThumbnailUrl(imageUrl + orderEntity.getThumbnailUrl());

        if (orderEntity.getPrice() != null) {
            mallOrderFrontInfoVO.setPrice(orderEntity.getPrice().stripTrailingZeros().toPlainString());
        }

        if (!orderEntity.getPostage() && orderEntity.getPostagePrice() != null) {
            mallOrderFrontInfoVO.setPostagePrice(orderEntity.getPostagePrice().stripTrailingZeros().toPlainString());
        }

        if (Objects.equals(orderEntity.getVirType(), MallProductVirTypeEnum.USAGE_OBJECT.getCode())) {
            MallProductEntity product = mallProductService.getMethodById(orderEntity.getProductId());
            if (product != null) {
                mallOrderFrontInfoVO.setMethod(product.getMethod());
                if (StringUtils.isNotBlank(product.getVirImage())) {
                    mallOrderFrontInfoVO.setVirImage(imageUrl + product.getVirImage());
                }
            }
        }

        return mallOrderFrontInfoVO;
    }

    @Override
    public void finish(Long id, Integer userId) {
        MallOrderEntity orderEntity = mallOrderDao.selectById(id);
        if (orderEntity == null) {
            throw new ServiceException("订单不存在");
        }
        if (!Objects.equals(userId, orderEntity.getUserId())) {
            throw new ServiceException("只有本人可以确认收货");
        }

        MallOrderEntity updateOrder = new MallOrderEntity()
                .setId(orderEntity.getId())
                .setStatus(MallOrderStatusEnum.FINISHED.getCode());
        mallOrderDao.updateById(updateOrder);

        mallOrderFinishService.deleteByOrderId(orderEntity.getId());
    }

    @Override
    public void refund(MallOrderRefundApplyDTO orderRefundApplyDTO, Integer userId) {
        MallOrderEntity orderEntity = mallOrderDao.selectById(orderRefundApplyDTO.getId());
        if (orderEntity == null) {
            throw new ServiceException("订单不存在");
        }
        if (!Objects.equals(userId, orderEntity.getUserId())) {
            throw new ServiceException("只有本人可以申请退款");
        }

        MallOrderEntity updateOrder = new MallOrderEntity()
                .setId(orderEntity.getId())
                .setRefundStatus(MallRefundStatusEnum.TO_REFUND.getCode())
                .setExplain(orderRefundApplyDTO.getExplain())
                .setRefundPhone(orderRefundApplyDTO.getPhone())
                .setApplicationTime(new Date());

        if (orderEntity.getRefundCount() == null) {
            updateOrder.setRefundCount(1);
        } else {
            updateOrder.setRefundCount(orderEntity.getRefundCount() + 1);
        }

        mallOrderDao.updateById(updateOrder);
    }

    @Override
    public MallRefundFrontInfoVO frontRefundInfo(Long id, Integer userId) {
        MallOrderEntity orderEntity = mallOrderDao.selectById(id);
        if (orderEntity == null) {
            throw new ServiceException("订单不存在");
        }
        if (!Objects.equals(userId, orderEntity.getUserId())) {
            throw new ServiceException("只有本人可以查看退款");
        }

        MallRefundFrontInfoVO refundFrontInfoVO = new MallRefundFrontInfoVO()
                .setId(id)
                .setNumber(orderEntity.getNumber())
                .setRefundStatus(orderEntity.getRefundStatus())
                .setThumbnailUrl(imageUrl + orderEntity.getThumbnailUrl())
                .setProductName(orderEntity.getProductName())
                .setQuantity(orderEntity.getQuantity())
                .setExplain(orderEntity.getExplain())
                .setApplicationTime(DateUtil.format(orderEntity.getApplicationTime(), "yyyy-MM-dd HH:mm"));

        if (orderEntity.getPrice() != null) {
            refundFrontInfoVO.setPrice(orderEntity.getPrice().stripTrailingZeros().toPlainString());
        }

        if (Objects.equals(MallRefundStatusEnum.REJECTED.getCode(), orderEntity.getRefundStatus())) {
            refundFrontInfoVO.setProcessTime(DateUtil.format(orderEntity.getProcessTime(), "yyyy-MM-dd HH:mm"))
                    .setReply(orderEntity.getReply());
        }

        return refundFrontInfoVO;
    }

    @Override
    public List<MallSimpleOrderVO> listSimplyByUserId(Integer userId) {
        List<MallOrderEntity> orderList = mallOrderDao.selectNumberByUserId(userId);

        return orderList.stream()
                .map(orderEntity -> new MallSimpleOrderVO()
                        .setId(orderEntity.getId())
                        .setNumber(orderEntity.getNumber()))
                .collect(Collectors.toList());
    }

    @Override
    public List<MallOrderFrontListVO> search(Integer userId, String keyword) {
        List<MallOrderEntity> orderList = mallOrderDao.selectListByUserIdAndKeyword(userId, keyword);

        return convertList(orderList);
    }

    @Override
    public MallQrCodeVO getQrcode(Long id) {
        MallOrderEntity orderEntity = mallOrderDao.selectById(id);
        if (orderEntity == null) {
            throw new ServiceException("订单不存在");
        }

        return new MallQrCodeVO()
                .setNumber(orderEntity.getVirNumber())
                .setUrl(imageUrl + orderEntity.getVirNumber() + ".jpg");
    }

    @Override
    @Transactional
    public void paySuccessByNumber(String number) {
        MallOrderEntity order = mallOrderDao.selectByOrderNumber(number);
        if (order == null) {
            throw new ServiceException("订单不存在");
        }

        if (Objects.equals(order.getStatus(), MallOrderStatusEnum.TO_PAY.getCode())) {
            order.setStatus(MallOrderStatusEnum.TO_DELIVER.getCode());

            // 生成电子券码
            processVirObject(order);

            MallOrderEntity updateOrder = new MallOrderEntity()
                    .setId(order.getId())
                    .setStatus(order.getStatus())
                    .setVirNumber(order.getVirNumber());
            mallOrderDao.updateById(updateOrder);

            // 积分记录
            if (order.getCredit() != null && order.getCredit() > 0) {
                int consumeCredit = order.getCredit() * order.getQuantity();
                MallCreditRecordEntity creditRecord = new MallCreditRecordEntity()
                        .setUserId(order.getUserId())
                        .setName("商品兑换")
                        .setCredit(consumeCredit * -1)
                        .setDate(DateUtil.format(new Date(), "yyyy-MM-dd"));
                mallCreditRecordService.save(creditRecord);
            }
        }
    }

    @Override
    public Integer getPayStatus(Long id, Integer userId) {
        MallOrderEntity orderEntity = mallOrderDao.selectById(id);
        if (orderEntity == null) {
            throw new ServiceException("订单不存在");
        }
        if (!Objects.equals(userId, orderEntity.getUserId())) {
            throw new ServiceException("只有本人可以查看支付状态");
        }

        return orderEntity.getStatus();
    }

    @Override
    @Transactional
    public void cancel(Long id, Integer userId) {
        MallOrderEntity orderEntity = mallOrderDao.selectById(id);
        if (orderEntity == null) {
            throw new ServiceException("订单不存在");
        }
        if (!Objects.equals(userId, orderEntity.getUserId())) {
            throw new ServiceException("只有本人可以取消订单");
        }

        MallOrderEntity updateOrder = new MallOrderEntity()
                .setId(id)
                .setStatus(MallOrderStatusEnum.CLOSED.getCode());
        mallOrderDao.updateById(updateOrder);

        // 返还积分
        if (orderEntity.getCredit() != null && orderEntity.getCredit() > 0) {
            int consumeCredit = orderEntity.getCredit() * orderEntity.getQuantity();
            oaUserService.refundCredit(userId, consumeCredit);
        }

        // 增加库存
        mallProductService.addStock(orderEntity.getProductId(), orderEntity.getQuantity());
    }

    @Override
    public MallOrderCreateVO pay(Long id, Integer userId, String openid, String ip) {
        MallOrderEntity order = mallOrderDao.selectById(id);
        if (order == null) {
            throw new ServiceException("订单不存在");
        }
        if (!Objects.equals(userId, order.getUserId())) {
            throw new ServiceException("只有本人可以付款");
        }

        return createWxOrder(openid, ip, order);
    }

    private List<MallOrderFrontListVO> convertList(List<MallOrderEntity> orderList) {
        return orderList.stream()
                .map(order -> {
                    MallOrderFrontListVO orderFrontListVO = new MallOrderFrontListVO()
                            .setId(order.getId())
                            .setNumber(order.getNumber())
                            .setType(order.getType())
                            .setStatus(order.getStatus())
                            .setRefundStatus(order.getRefundStatus())
                            .setThumbnailUrl(imageUrl + order.getThumbnailUrl())
                            .setProductName(order.getProductName())
                            .setAttrValue(order.getAttrValue())
                            .setQuantity(order.getQuantity())
                            .setPostage(order.getPostage())
                            .setCreateDate(order.getCreateTime());
                    if (order.getPrice() != null) {
                        orderFrontListVO.setPrice(order.getPrice().stripTrailingZeros().toPlainString());
                    }
                    if (!order.getPostage() && order.getPostagePrice() != null) {
                        orderFrontListVO.setPostagePrice(order.getPostagePrice().stripTrailingZeros().toPlainString());
                    }
                    return orderFrontListVO;
                })
                .collect(Collectors.toList());
    }

    private MallOrderCreateVO createWxOrder(String openid, String ip, MallOrderEntity order) {
        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        orderRequest.setBody("兑换商品");
        orderRequest.setOutTradeNo(order.getNumber());

        BigDecimal productFee = order.getPrice().multiply(new BigDecimal(order.getQuantity()));
        if (!order.getPostage() && order.getPostagePrice() != null) {
            productFee = productFee.add(order.getPostagePrice());
        }
        orderRequest.setTotalFee(BaseWxPayRequest.yuanToFen(productFee.stripTrailingZeros().toPlainString()));//元转成分
        orderRequest.setOpenid(openid);
        orderRequest.setSpbillCreateIp(ip);
        orderRequest.setTradeType("JSAPI");

        WxPayMpOrderResult wxPayMpOrderResult;
        try {
            wxPayMpOrderResult = wxPayService.createOrder(orderRequest);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ServiceException("支付失败，请稍后重试！");
        }

        return new MallOrderCreateVO()
                .setId(order.getId())
                .setPay(true)
                .setAppId(wxPayMpOrderResult.getAppId())
                .setTimeStamp(wxPayMpOrderResult.getTimeStamp())
                .setNonceStr(wxPayMpOrderResult.getNonceStr())
                .setPackageValue(wxPayMpOrderResult.getPackageValue())
                .setPaySign(wxPayMpOrderResult.getPaySign())
                .setSignType(wxPayMpOrderResult.getSignType());
    }

    // 处理虚拟物品订单
    private void processVirObject(MallOrderEntity order) {
        if (Objects.equals(order.getType(), MallProductTypeEnum.VIR_OBJECT.getCode())) {
            if (Objects.equals(order.getVirType(), MallProductVirTypeEnum.ELE_OBJECT.getCode())) {
                while (true) {
                    String code = RandomUtil.getRandNumberStr(12);
                    if (mallOrderDao.selectByVirNumber(code) == null) {
                        order.setVirNumber(code);
                        String codeImage = order.getVirNumber() + ".jpg";
                        QRCodeUtil.createQrCode(shopUrl + "?number=" + order.getVirNumber(), imageDir, codeImage);
                        break;
                    }
                }
            } else if (Objects.equals(order.getVirType(), MallProductVirTypeEnum.USAGE_OBJECT.getCode())) {
                order.setStatus(MallOrderStatusEnum.FINISHED.getCode());
            }
        }
    }

}